package com.controller;

import com.encoder.ChatMessageDecoder;
import com.encoder.ChatMessageEncoder;
import com.entity.FriendMessage;
import com.entity.GroupMessage;
import com.entity.GroupUser;
import com.entity.UserInfo;
import com.service.*;
import com.utils.spring.SpringContextUtil;
import com.vo.ChatMessageVO;
import com.vo.ChatMsgType;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.SpringConfigurator;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Data
@Component
@ServerEndpoint(
        value = "/websocketServer/{userId}",
        encoders = {ChatMessageEncoder.class},
        decoders = {ChatMessageDecoder.class}
        )
public class WebsocketController {

    //线程安全的map集合，用来存放每个客户端对应的ProductWebSocket对象
    //保存所有连接的用户
    private static ConcurrentHashMap<String,WebsocketController> connectedUsers = new ConcurrentHashMap();

    private Session session;//用户连接
    private String userId;//用户名

    private String toUserId;//表示正在和谁聊天
    private String toGroupId;//表示正在哪个群聊天


    //各个业务类
    private FriendMessageService friendMessageService; //好友消息业务类
    private UserInfoService userInfoService;//用户业务类
    private GroupMessageService groupMessageService;//群消息业务类
    private GroupUserService groupUserService;//群用户业务类

    public WebsocketController(){
        try {
            friendMessageService = SpringContextUtil.getBean(FriendMessageService.class);
            userInfoService = SpringContextUtil.getBean(UserInfoService.class);
            groupMessageService = SpringContextUtil.getBean(GroupMessageService.class);
            groupUserService = SpringContextUtil.getBean(GroupUserService.class);
        }catch (NullPointerException e){
            System.out.println("第一次创建websocket对象");
        }
    }

    /**
     * 建立连接
     * @param session
     */
    @OnOpen
    public void onOpen(@PathParam("userId")String userId, Session session) throws IOException {
        System.out.println("连接成功 userId："+userId);
        this.session = session;
        this.userId = userId;

        //添加map集合
        connectedUsers.put(userId,this);

        //推送给所有在线人用户在线情况
        sendOnlineUsers();

    }

    /**
     * 接收前端传来的消息
     * @param session
     * @param message
     * @throws IOException
     */
    @OnMessage
    public void onMessage(Session session,ChatMessageVO message) throws IOException {
        //处理消息类型
        MsgTypeHandle(message);

    }

    /**
     * 处理消息类型
     * @param message
     * @throws IOException
     */
    private void MsgTypeHandle(ChatMessageVO message) throws IOException {
        String msgType = message.getType();
        if(msgType.equals(ChatMsgType.FRIEND_MSG.toString())){//如果是好友聊天消息...

            //得到好友消息对象
            FriendMessage friendMessage = message.getFriendMessage();
            friendMessage.setFromUserId(parseInt(message.getFrom()));
            friendMessage.setToUserId(parseInt(message.getDestination()));

            //判断指定用户是否在线
            if(isOnLine(message.getDestination())){
                //获得对方正在和谁聊天的id
                String toUserId = connectedUsers.get(message.getDestination()).getToUserId();
                //判断对方和谁聊天的是不是自己
                if(this.userId.equals(toUserId)){
                    friendMessage.setIsRead(1);//设置为已读
                }else{
                    friendMessage.setIsRead(0);//设置为未读
                }
            }else {
                friendMessage.setIsRead(0);//设置为未读
            }

            //查询发消息用户的信息
            UserInfo userInfo = userInfoService.getById(parseInt(message.getFrom()));

            if(message.getFriendMessage().getIsBack().equals(0)){//未撤回消息
                //插入数据库
                friendMessage = friendMessageService.addFiendMessage(friendMessage);
                message.setFriendMessage(friendMessage);

            }else {//是撤回消息
                //数据库修改撤回状态
                friendMessageService.editBackById(friendMessage.getId());
            }
            //设置发消息的用户信息
            message.getFriendMessage().setUserInfo((userInfo));
            //推送给自己
            sendMessage(message);
            //推送目标消息
            sendDestination(message);


        }else if (msgType.equals(ChatMsgType.ALL_USER_ONLINE.toString())){//所有用户在线情况消息...
            //返回所有用户的在线情况
            sendOnlineUsers();
        }
        else if (msgType.equals(ChatMsgType.FRIEND_TO.toString())){//在和哪个好友聊天(一打开好友聊天界面时)...
            this.toUserId = message.getDestination();
            if(this.toUserId != null) {
                //和好友聊天的未读消息全部变为已读
                friendMessageService.editToRead(parseInt(this.userId), parseInt(this.toUserId));
            }
        }
        else if (msgType.equals(ChatMsgType.FRIEND_VERIFY.toString())){//好友请求验证消息
            //推送给目标和自己
            sendMessage(message);
            sendDestination(message);
        }
        else if (msgType.equals(ChatMsgType.GROUP_MSG.toString())){//群聊天消息
            //得到群消息对象
            GroupMessage groupMessage = message.getGroupMessage();
            groupMessage.setFromUserId(parseInt(message.getFrom()));
            groupMessage.setToGroupId(parseInt(message.getDestination()));

            //查询发消息群成员的信息
            GroupUser groupUser = null;
            List<GroupUser> groupUserAll = groupUserService.getAllByGroupId(parseInt(message.getDestination()));
            for (GroupUser user : groupUserAll) {
                //取得自己的群成员信息
                if (user.getUserInfo().getId().toString().equals(message.getFrom())){
                    groupUser = user;
                    //groupUserAll.remove(user);
                    break;
                }
            }

            if(message.getGroupMessage().getIsBack().equals(0)){//未撤回消息
                //插入数据库
                groupMessage = groupMessageService.addGroupMessage(groupMessage);
                message.setGroupMessage(groupMessage);
            }else {//是撤回消息
                //数据库修改撤回状态
                groupMessageService.editBackById(message.getGroupMessage().getId());
            }
            //设置发消息的用户信息
            message.getGroupMessage().setFromGroupUser(groupUser);

            //推送给自己
            //sendMessage(message);

            //遍历推送给不同的人
            for (GroupUser user : groupUserAll) {
                //判断是否在线
                String uId = user.getUserInfo().getId().toString();
                if(isOnLine(uId)){
                    //推送消息
                    connectedUsers.get(uId).sendMessage(message);
                    //判断对方是否再此群里聊天
                    if(!(message.getDestination().equals(connectedUsers.get(uId).getToGroupId()))){
                        //未读消息加一
                        groupUserService.editNotReadCount(
                                groupUserService.getNotReadCount(user.getUserId(),user.getGroupId())+1,
                                user.getUserId(),
                                user.getGroupId()
                        );
                    }
                }else{
                    //未读消息加一
                    groupUserService.editNotReadCount(
                            groupUserService.getNotReadCount(user.getUserId(),user.getGroupId())+1,
                            user.getUserId(),
                            user.getGroupId()
                    );
                }
            }


        }else if (msgType.equals(ChatMsgType.GROUP_TO.toString())){//表示正在哪个群聊天
            this.toGroupId = message.getDestination();
            if(this.toGroupId != null) {
                groupUserService.editNotReadCount(0,parseInt(message.getFrom()),parseInt(message.getDestination()));
            }
        }
        else if (msgType.equals(ChatMsgType.GROUP_NOTIFICATION.toString())){//群系统消息
            //查询发消息群成员的信息
            List<GroupUser> groupUserAll = groupUserService.getAllByGroupId(parseInt(message.getDestination()));

            //遍历推送给不同的人
            for (GroupUser user : groupUserAll) {
                //判断是否在线
                String uId = user.getUserInfo().getId().toString();
                if(isOnLine(uId)){
                    //推送消息
                    connectedUsers.get(uId).sendMessage(message);
                }
            }
        }
    }

    /**
     * 推送消息
     * @param message
     */
    public void sendMessage(ChatMessageVO message) {
        this.session.getAsyncRemote().sendObject(message); //推送消息
    }
    /**
     * 推送目标消息
     * @param message
     * @return 返回用户是否在线
     */
    public boolean sendDestination(ChatMessageVO message){
        //推送给好友
        WebsocketController websocketController = connectedUsers.get(message.getDestination());
        if (websocketController!=null){
            websocketController.sendMessage(message);
            return true;
        }
        return false;
    }

    /**
     * 判断目标是否在线
     * @param destination 目标
     * @return
     */
    public boolean isOnLine(String destination){
        WebsocketController websocketController = connectedUsers.get(destination);
        return websocketController!=null?true:false;
    }
    /**
     * 发给所有人
     */
    public void sendInfo(ChatMessageVO message) throws IOException {
        for (Map.Entry<String, WebsocketController> socket : connectedUsers.entrySet()) {
            socket.getValue().sendMessage(message);
        }
    }


    /**
     * 断开连接
     * @param session
     * @throws IOException
     */
    @OnClose
    public void onClose(Session session) throws IOException {
        System.out.println("断开连接");

        session.close();//关闭当前连接
        connectedUsers.remove(userId);
        //推送一下当前在线所有人
        sendOnlineUsers();
    }

    /**
     * 连接异常
     * @param session
     * @param throwable
     */
    @OnError
    public void onError(Session session,Throwable throwable){
        System.out.println("session = " + session + ", throwable = " + throwable);
    }

    /**
     * 获得当前在线用户数量
     * @return
     */
    private Integer getOnLineCount(){
        return connectedUsers.entrySet().size();
    }

    /**
     * 推送当前在线所有人
     */
    private void sendOnlineUsers() throws IOException {
        //获得在线的在线人数
        ChatMessageVO message = new ChatMessageVO();
        message.setType(ChatMsgType.ALL_USER_ONLINE.toString());
        String online = "";
        for (Map.Entry<String, WebsocketController> entry : connectedUsers.entrySet()) {
            online+=entry.getKey()+",";
        }
        if(online.length() != 0){
            message.setOnlineUsers(online.substring(0,online.length()-1));
            //推送给所有人
            sendInfo(message);
        }

    }

    /**
     * 转换id为int
     * @param id
     * @return
     */
    private static Integer parseInt(String id){
        return Integer.parseInt(id);
    }
}
